<template>
  <div class="chat-container">
    <div class="chat-head">
      <button v-if="sidebarStore.isCollapsed" @click="restoreSidebar" class="restore-sidebar-btn" title="展开侧边栏">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M15 18l6-6-6-6"/>
        </svg>
      </button>
      
      <div class="left-head">

      <div class="model-choose">
          <select v-model="selectedModel" @change="onModelChange" class="model-select">
            <option v-for="model in presetModels" :key="model.id" :value="model.id">
              {{ model.name }}
            </option>
          </select>
      </div>
      <div @click="openCustomConfigModal" class="add-model-btn">
        +
      </div>
      </div>
      <div class="info" @click="openInfoPanel">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 120" width="120" height="120" style="width: 100%; height: 100%; transform: translate3d(0px, 0px, 0px); content-visibility: visible;" preserveAspectRatio="xMidYMid meet"><defs><clipPath id="__lottie_element_49"><rect width="120" height="120" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_49)"><g style="display: block;" transform="matrix(1,0,0,1,60.00299835205078,53.121002197265625)" opacity="1"><g opacity="1" transform="matrix(5,0,0,5,0,0)"><path stroke-linecap="round" stroke-linejoin="round" fill-opacity="0" stroke="rgb(153,153,153)" stroke-opacity="1" stroke-width="1.54" d=" M6.5980000495910645,-0.9779999852180481 C6.598999977111816,-0.9269999861717224 6.599999904632568,-0.8759999871253967 6.599999904632568,-0.824999988079071 C6.599999904632568,-0.824999988079071 6.599999904632568,5.224999904632568 6.599999904632568,5.224999904632568 C6.599999904632568,5.224999904632568 8.206000328063965,7.059999942779541 8.206000328063965,7.059999942779541 C8.329999923706055,7.202000141143799 8.229000091552734,7.425000190734863 8.039999961853027,7.425000190734863 C8.039999961853027,7.425000190734863 -8.039999961853027,7.425000190734863 -8.039999961853027,7.425000190734863 C-8.229000091552734,7.425000190734863 -8.329999923706055,7.202000141143799 -8.206000328063965,7.059999942779541 C-8.206000328063965,7.059999942779541 -6.599999904632568,5.224999904632568 -6.599999904632568,5.224999904632568 C-6.599999904632568,5.224999904632568 -6.599999904632568,5.224999904632568 -6.599999904632568,5.224999904632568 C-6.599999904632568,5.224999904632568 -6.599999904632568,-0.824999988079071 -6.599999904632568,-0.824999988079071 C-6.599999904632568,-4.46999979019165 -3.6449999809265137,-7.425000190734863 0,-7.425000190734863 C0,-7.425000190734863 0,-7.425000190734863 0,-7.425000190734863"></path></g></g><g style="display: block;" transform="matrix(1,0,0,1,59.98699951171875,103.98400115966797)" opacity="1"><g opacity="1" transform="matrix(5,0,0,5,0,0)"><path stroke-linecap="round" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(153,153,153)" stroke-opacity="1" stroke-width="1.54" d=" M2.200000047683716,0 C2.200000047683716,0 -2.200000047683716,0 -2.200000047683716,0"></path></g></g><g style="display: block;" transform="matrix(0.9983727931976318,0.05702386423945427,-0.05702386423945427,0.9983727931976318,83.47799682617188,23.959001541137695)" opacity="1"><g opacity="1" transform="matrix(5,0,0,5,0,0)"><path fill="rgb(232,52,65)" fill-opacity="1" d=" M0,-2.5 C1.3797500133514404,-2.5 2.5,-1.3797500133514404 2.5,0 C2.5,1.3797500133514404 1.3797500133514404,2.5 0,2.5 C-1.3797500133514404,2.5 -2.5,1.3797500133514404 -2.5,0 C-2.5,-1.3797500133514404 -1.3797500133514404,-2.5 0,-2.5z"></path></g></g></g></svg>
      </div>
    </div>
    <div class="messages-container" ref="messagesContainer">
      <div v-for="(message, index) in messages" :key="index" 
           :class="['message', message.role, message.error ? 'error' : '', message.streaming ? 'streaming' : '']">
        <div class="content">
          <div class="message-text" v-html="getRenderedMarkdown(message)"></div>
          <div v-if="message.streaming" class="typing-indicator">
            <span></span><span></span><span></span>
          </div>
          <div v-if="message.error" class="error-message">
            {{ message.error }}
          </div>
        </div>
      </div>
      
    </div>

    <div class="input-area">
      <textarea 
        v-model="userInput" 
        placeholder="有什么可以帮助你？" 
        @keydown.enter.prevent="sendMessage"
        :disabled="loading"
        rows="1"
        ref="textAreaRef"
      ></textarea>
      <div class="send-button" @click="sendMessage" :disabled="loading || !userInput.trim()">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="100" height="100" style="width: 100%; height: 100%; transform: translate3d(0px, 0px, 0px); content-visibility: visible;" preserveAspectRatio="xMidYMid meet"><defs><clipPath id="__lottie_element_10"><rect width="100" height="100" x="0" y="0"></rect></clipPath><clipPath id="__lottie_element_12"><path d="M0,0 L240,0 L240,112 L0,112z"></path></clipPath><clipPath id="__lottie_element_16"><path d="M0,0 L3170,0 L3170,1783 L0,1783z"></path></clipPath><g id="__lottie_element_19"><g style="display: block;" transform="matrix(13.170000076293945,0,0,13.170000076293945,-12220.3642578125,-8267.9521484375)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,1051.81201171875,698.25)"><path stroke-linecap="butt" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(175,127,84)" stroke-opacity="1" stroke-width="0" d=" M40,0 C40,0 40,0 40,0 C40,22.076000213623047 22.076000213623047,40 0,40 C0,40 0,40 0,40 C-22.076000213623047,40 -40,22.076000213623047 -40,0 C-40,0 -40,0 -40,0 C-40,-22.076000213623047 -22.076000213623047,-40 0,-40 C0,-40 0,-40 0,-40 C22.076000213623047,-40 40,-22.076000213623047 40,0z"></path><path fill="rgb(0,0,13)" fill-opacity="1" d=" M40,0 C40,0 40,0 40,0 C40,22.076000213623047 22.076000213623047,40 0,40 C0,40 0,40 0,40 C-22.076000213623047,40 -40,22.076000213623047 -40,0 C-40,0 -40,0 -40,0 C-40,-22.076000213623047 -22.076000213623047,-40 0,-40 C0,-40 0,-40 0,-40 C22.076000213623047,-40 40,-22.076000213623047 40,0z"></path></g></g></g><clipPath id="__lottie_element_23"><path d="M0,0 L2500,0 L2500,1406 L0,1406z"></path></clipPath><linearGradient id="__lottie_element_29" spreadMethod="pad" gradientUnits="userSpaceOnUse" x1="-98" y1="137" x2="-5" y2="51"><stop offset="0%" stop-color="rgb(255,255,255)"></stop><stop offset="100%" stop-color="rgb(0,0,0)"></stop></linearGradient><linearGradient id="__lottie_element_36" spreadMethod="pad" gradientUnits="userSpaceOnUse" x1="-98" y1="137" x2="-5" y2="51"><stop offset="0%" stop-color="rgb(255,255,255)"></stop><stop offset="100%" stop-color="rgb(0,0,0)"></stop></linearGradient><mask id="__lottie_element_19_1" mask-type="alpha"><use xlink:href="#__lottie_element_19"></use></mask></defs><g clip-path="url(#__lottie_element_10)"><g clip-path="url(#__lottie_element_12)" style="display: block;" transform="matrix(1.1200000047683716,0,0,1.1200000047683716,-84.39999389648438,-12.720001220703125)" opacity="1"><g style="display: block;" transform="matrix(1,0,0,1,-931.81201171875,-642.25)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,1051.81201171875,698.25)"><path stroke-linecap="butt" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(175,127,84)" stroke-opacity="1" stroke-width="0" d=" M40,0 C40,0 40,0 40,0 C40,22.076000213623047 22.076000213623047,40 0,40 C0,40 0,40 0,40 C-22.076000213623047,40 -40,22.076000213623047 -40,0 C-40,0 -40,0 -40,0 C-40,-22.076000213623047 -22.076000213623047,-40 0,-40 C0,-40 0,-40 0,-40 C22.076000213623047,-40 40,-22.076000213623047 40,0z"></path><path fill="rgb(13,13,13)" fill-opacity="1" d=" M40,0 C40,0 40,0 40,0 C40,22.076000213623047 22.076000213623047,40 0,40 C0,40 0,40 0,40 C-22.076000213623047,40 -40,22.076000213623047 -40,0 C-40,0 -40,0 -40,0 C-40,-22.076000213623047 -22.076000213623047,-40 0,-40 C0,-40 0,-40 0,-40 C22.076000213623047,-40 40,-22.076000213623047 40,0z"></path></g></g><g clip-path="url(#__lottie_element_16)" style="display: block;" transform="matrix(0.07500000298023224,0,0,0.07500000298023224,-2.200000047683716,-13.612500190734863)" opacity="1"><g style="display: block;" mask="url(#__lottie_element_19_1)"><g clip-path="url(#__lottie_element_23)" transform="matrix(1,0,0,1,401,221.5)" opacity="1"><g style="display: block;" transform="matrix(1,0,0,1,1240,700)" opacity="0.8"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="url(#__lottie_element_36)" fill-opacity="1" d=" M-74.125,10.875 C-74.125,10.875 -69,-36.375 -74.125,10.875 C-79.25,58.125 -114,110.125 -126.125,113 C-138.25,115.875 -99.625,194.875 -84.125,168.25 C-62.125,136.625 3.875,108.75 32.375,109.625 C60.875,110.5 30.940000534057617,55.819000244140625 3.0199999809265137,29.871999740600586 C-22.16900062561035,6.464000225067139 -74.125,10.637999534606934 -74.125,10.875z"></path><path stroke-linecap="butt" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(255,255,255)" stroke-opacity="0.87" stroke-width="0" d=" M-74.125,10.875 C-74.125,10.875 -69,-36.375 -74.125,10.875 C-79.25,58.125 -114,110.125 -126.125,113 C-138.25,115.875 -99.625,194.875 -84.125,168.25 C-62.125,136.625 3.875,108.75 32.375,109.625 C60.875,110.5 30.940000534057617,55.819000244140625 3.0199999809265137,29.871999740600586 C-22.16900062561035,6.464000225067139 -74.125,10.637999534606934 -74.125,10.875z"></path></g></g><g style="display: block;" transform="matrix(1,0,0,1,1239.875,699.875)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0.125,-0.25)"><path fill="rgb(255,255,255)" fill-opacity="1" d=" M-125.875,102 C-145.70899963378906,102.14199829101562 -161.53700256347656,112.69400024414062 -170.7429962158203,126.77400207519531 C-177.78199768066406,137.5399932861328 -179.87600708007812,149.375 -179.43800354003906,161.375 C-178.4770050048828,187.7429962158203 -155.8090057373047,214.60899353027344 -121.31199645996094,215.93800354003906 C-97.76499938964844,216.84500122070312 -80.2300033569336,202.57899475097656 -71.6969985961914,187.18899536132812 C-68.4749984741211,181.3780059814453 -66.80500030517578,175.031005859375 -66.18800354003906,169.8280029296875 C-64.45899963378906,155.24099731445312 -67.125,143.25 -72.5,132.43800354003906 C-76.04000091552734,125.31800079345703 -91.875,103.18800354003906 -122.50199890136719,102.05000305175781 C-123.6050033569336,102.00900268554688 -124.72899627685547,101.99199676513672 -125.875,102z"></path><path stroke-linecap="butt" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(255,255,255)" stroke-opacity="1" stroke-width="0" d=" M-125.875,102 C-145.70899963378906,102.14199829101562 -161.53700256347656,112.69400024414062 -170.7429962158203,126.77400207519531 C-177.78199768066406,137.5399932861328 -179.87600708007812,149.375 -179.43800354003906,161.375 C-178.4770050048828,187.7429962158203 -155.8090057373047,214.60899353027344 -121.31199645996094,215.93800354003906 C-97.76499938964844,216.84500122070312 -80.2300033569336,202.57899475097656 -71.6969985961914,187.18899536132812 C-68.4749984741211,181.3780059814453 -66.80500030517578,175.031005859375 -66.18800354003906,169.8280029296875 C-64.45899963378906,155.24099731445312 -67.125,143.25 -72.5,132.43800354003906 C-76.04000091552734,125.31800079345703 -91.875,103.18800354003906 -122.50199890136719,102.05000305175781 C-123.6050033569336,102.00900268554688 -124.72899627685547,101.99199676513672 -125.875,102z"></path></g></g><g style="display: block;" transform="matrix(1.1100000143051147,0,0,1.1100000143051147,1385,576.5)" opacity="1"><path fill="rgb(255,255,255)" fill-opacity="1" d=" M43,-63.4379997253418 C43,-63.4379997253418 31,-59.6879997253418 31,-59.6879997253418 C31,-59.6879997253418 -299,46.0620002746582 -299,46.0620002746582 C-299,46.0620002746582 -318.5450134277344,53.125 -318.5539855957031,72.81300354003906 C-318.56298828125,91.875 -303.875,99.43800354003906 -303.875,99.43800354003906 C-303.875,99.43800354003906 -171.56199645996094,165.31300354003906 -165.25,168.375 C-158.93800354003906,171.43800354003906 -155.06199645996094,176.25 -152.06199645996094,183.18699645996094 C-149.06199645996094,190.125 -85.75,317.5 -85.75,317.5 C-85.75,317.5 -79.01599884033203,332.56298828125 -59.257999420166016,332.81298828125 C-40,333.06298828125 -32.75,315.5 -32.75,315.5 C-32.75,315.5 72.875,-12.687999725341797 74.43800354003906,-18.187999725341797 C76,-23.687999725341797 77.43800354003906,-29.812000274658203 77.43800354003906,-29.812000274658203 C77.43800354003906,-29.812000274658203 80.09700012207031,-44.6619987487793 68.74400329589844,-55.310001373291016 C56.8129997253418,-66.5 43,-63.4379997253418 43,-63.4379997253418z"></path><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill="url(#__lottie_element_29)" fill-opacity="1" d="M0 0"></path></g><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path stroke-linecap="butt" stroke-linejoin="miter" fill-opacity="0" stroke-miterlimit="4" stroke="rgb(255,255,255)" stroke-opacity="1" stroke-width="0" d=" M43,-63.4379997253418 C43,-63.4379997253418 31,-59.6879997253418 31,-59.6879997253418 C31,-59.6879997253418 -299,46.0620002746582 -299,46.0620002746582 C-299,46.0620002746582 -318.5450134277344,53.125 -318.5539855957031,72.81300354003906 C-318.56298828125,91.875 -303.875,99.43800354003906 -303.875,99.43800354003906 C-303.875,99.43800354003906 -171.56199645996094,165.31300354003906 -165.25,168.375 C-158.93800354003906,171.43800354003906 -155.06199645996094,176.25 -152.06199645996094,183.18699645996094 C-149.06199645996094,190.125 -85.75,317.5 -85.75,317.5 C-85.75,317.5 -79.01599884033203,332.56298828125 -59.257999420166016,332.81298828125 C-40,333.06298828125 -32.75,315.5 -32.75,315.5 C-32.75,315.5 72.875,-12.687999725341797 74.43800354003906,-18.187999725341797 C76,-23.687999725341797 77.43800354003906,-29.812000274658203 77.43800354003906,-29.812000274658203 C77.43800354003906,-29.812000274658203 80.09700012207031,-44.6619987487793 68.74400329589844,-55.310001373291016 C56.8129997253418,-66.5 43,-63.4379997253418 43,-63.4379997253418z"></path></g></g></g></g></g></g></g></svg>
      </div>
    </div>
    <div class="window-footer">
      <span>内容由ai生成，仅供参考，请仔细甄别</span>
    </div>
    <div v-if="showConnectionWarning" class="connection-warning">
      <div class="warning-content">
        <h3>连接问题</h3>
        <p>无法连接到服务器，请检查：</p>
        <ul>
          <li>后端服务是否运行（localhost:8080）</li>
          <li>网络连接是否正常</li>
          <li>浏览器控制台是否有错误信息</li>
        </ul>
        <button @click="showConnectionWarning = false">知道了</button>
      </div>
    </div>
    
    <!-- 自定义配置弹窗 -->
    <div v-if="showCustomConfigModal" class="modal-overlay" @click="showCustomConfigModal = false">
      <div class="modal-content" @click.stop>
        <div class="modal-header">
          <h3>自定义模型配置</h3>
          <button class="close-btn" @click="showCustomConfigModal = false">×</button>
        </div>
        <div class="modal-body">
          <div class="config-input-group">
            <label>API URL:</label>
            <input v-model="customConfig.apiUrl" placeholder="https://api.example.com/v1/chat/completions" class="config-input" />
            <div v-if="validationErrors.apiUrl" class="error-message">{{ validationErrors.apiUrl }}</div>
          </div>
          <div class="config-input-group">
            <label>API Key:</label>
            <input v-model="customConfig.apiKey" type="password" placeholder="输入API密钥" class="config-input" />
            <div v-if="validationErrors.apiKey" class="error-message">{{ validationErrors.apiKey }}</div>
          </div>
          <div class="config-input-group">
            <label>模型名称:</label>
            <input v-model="customConfig.modelName" placeholder="例如: gpt-3.5-turbo" class="config-input" />
            <div v-if="validationErrors.modelName" class="error-message">{{ validationErrors.modelName }}</div>
          </div>
        </div>
        <div class="modal-footer">
          <button @click="saveCustomConfig" class="save-config-btn">保存配置</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, watch } from 'vue'
import { marked } from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/github-dark.css'
import 'highlightjs-line-numbers.js'
import { useSidebarStore } from '@/stores/sidebar'
import { useRouter } from 'vue-router'

// 使用Pinia store
const sidebarStore = useSidebarStore()
const router = useRouter()

// 响应式数据
const userInput = ref('')
const loading = ref(false)
const messagesContainer = ref(null)
const textAreaRef = ref(null)
const isConnected = ref(false)
const showConnectionWarning = ref(false)

// 模型管理相关数据
const selectedModel = ref('')
const presetModels = ref([
  {
    id: 'qwen-plus',
    name: '通义千问 Plus',
    provider: '阿里云',
    apiUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
    apiKey: import.meta.env.VITE_DASHSCOPE_API_KEY || '',
    modelName: 'qwen-plus'
  }
])
// 定义Message接口
interface Message {
  role: 'user' | 'ai' | 'system'
  content: string
  error?: string
  streaming?: boolean // 标记是否为流式消息
}

// 为messages添加类型注解
const messages = ref<Message[]>([])

// 流式消息的引用
const streamingMessageRef = ref<Message | null>(null)

// Markdown渲染缓存
const markdownCache = ref(new Map<string, string>())

// 使用同步版本的marked.parse
const renderMarkdownSync = (markdownText: string): string => {
  if (!markdownText) return ''
  markdownText = markdownText.trim()
  // 检查缓存
  if (markdownCache.value.has(markdownText)) {
    return markdownCache.value.get(markdownText)!
  }
  
  try {
    // 配置marked选项，集成highlight.js进行语法高亮
    marked.setOptions({
      breaks: true, // 将换行符转换为<br>
      gfm: true,    // 启用GitHub风格的Markdown
      async: false // 使用同步模式
    })
    
    const html = marked.parse(markdownText) as string
    
    // 缓存结果
    markdownCache.value.set(markdownText, html)
    
    // 在下一个tick触发highlight.js的高亮和行号显示
    nextTick(() => {
      document.querySelectorAll('pre code').forEach((block) => {
        hljs.highlightElement(block as HTMLElement)
        // 添加行号
        ;(window as any).hljs.lineNumbersBlock(block as HTMLElement)
        
        // 获取语言类型并设置data-language属性
        const preElement = block.parentElement
        if (preElement) {
          const languageMatch = block.className.match(/language-(\w+)/)
          if (languageMatch && languageMatch[1]) {
            preElement.setAttribute('data-language', languageMatch[1])
          }
        }
      })
    })
    
    return html
  } catch (error) {
    console.warn('Markdown解析失败:', error)
    return markdownText // 如果解析失败，返回原始文本
  }
}

/**
 * 获取已渲染的Markdown内容（同步方法，用于模板）
 * @param message 消息对象
 * @returns 渲染后的HTML或原始文本
 */
const getRenderedMarkdown = (message: Message): string => {
  if (message.role !== 'ai' || message.streaming) {
    return message.content
  }
  
  return renderMarkdownSync(message.content)
}
const customConfig = ref({
  apiUrl: '',
  apiKey: '',
  modelName: ''
})

// 当前使用的API配置
const currentApiConfig = ref({
  apiUrl: '',
  apiKey: '',
  modelName: ''
})

// 弹窗控制
const showCustomConfigModal = ref(false)

// 验证状态
const validationErrors = ref({
  apiUrl: '',
  apiKey: '',
  modelName: ''
})
const restoreSidebar=()=>{
  sidebarStore.expand()
}
/**
 * 验证自定义配置
 * @returns 是否通过验证
 */
const validateCustomConfig = () => {
  // 清空之前的错误信息
  validationErrors.value = { apiUrl: '', apiKey: '', modelName: '' }
  
  let isValid = true
  
  if (!customConfig.value.apiUrl.trim()) {
    validationErrors.value.apiUrl = 'API URL不能为空'
    isValid = false
  } else if (!customConfig.value.apiUrl.startsWith('http')) {
    validationErrors.value.apiUrl = 'API URL必须以http或https开头'
    isValid = false
  }
  
  if (!customConfig.value.apiKey.trim()) {
    validationErrors.value.apiKey = 'API Key不能为空'
    isValid = false
  }
  
  if (!customConfig.value.modelName.trim()) {
    validationErrors.value.modelName = '模型名称不能为空'
    isValid = false
  }
  
  return isValid
}

    /**
     * 模型切换处理
     * 保存选中的模型到localStorage并更新当前API配置
     */
    const onModelChange = () => {
      // 保存选中的模型到localStorage
      if (selectedModel.value) {
        localStorage.setItem('selectedModel', selectedModel.value)
      }
      
      if (selectedModel.value) {
        // 选择预置模型
        const model = presetModels.value.find(m => m.id === selectedModel.value)
        if (model) {
          currentApiConfig.value = {
            apiUrl: model.apiUrl,
            apiKey: model.apiKey,
            modelName: model.modelName
          }
          
          // 检查API密钥是否配置
          if (!currentApiConfig.value.apiKey) {
            messages.value.push({
              role: 'ai',
              content: `请配置${model.provider}的API密钥。您需要在环境变量中设置相应的API密钥。`
            })
          }
        }
      }
    }

    /**
     * 打开自定义配置弹窗
     */
    const openCustomConfigModal = () => {
      showCustomConfigModal.value = true
      // 每次打开弹窗时清空配置内容和错误信息
      customConfig.value = {
        apiUrl: '',
        apiKey: '',
        modelName: ''
      }
      validationErrors.value = { apiUrl: '', apiKey: '', modelName: '' }
    }

    /**
     * 保存自定义配置
     * 将自定义模型配置保存到localStorage并添加到预设模型列表
     */
    const saveCustomConfig = () => {
      // 先进行验证
      if (!validateCustomConfig()) {
        return
      }

      // 生成唯一的模型ID
      const modelId = 'custom_' + Date.now()
      
      // 创建新的自定义模型
      const newCustomModel = {
        id: modelId,
        name: customConfig.value.modelName,
        provider: '自定义',
        apiUrl: customConfig.value.apiUrl,
        apiKey: customConfig.value.apiKey,
        modelName: customConfig.value.modelName
      }
      
      // 添加新的自定义模型到预设模型列表
      presetModels.value.push(newCustomModel)
      
      // 保存整个模型列表到localStorage
      localStorage.setItem('customModels', JSON.stringify(presetModels.value))
      
      // 自动选择新添加的自定义模型
      selectedModel.value = modelId
      
      // 更新当前配置
      currentApiConfig.value = { ...customConfig.value }
      
      // 关闭弹窗
      showCustomConfigModal.value = false
      
    }

    /**
     * 删除模型
     */
    const deleteModel = (modelId: string) => {
      // 防止删除默认模型
      if (modelId === 'qwen-plus') {
        return
      }
      
      // 从模型列表中删除
      const index = presetModels.value.findIndex(m => m.id === modelId)
      if (index !== -1) {
        presetModels.value.splice(index, 1)
        
        // 更新localStorage中的模型列表
        localStorage.setItem('customModels', JSON.stringify(presetModels.value))
      }
      
      // 如果删除的是当前选中的模型，则选择第一个模型
      if (selectedModel.value === modelId) {
        if (presetModels.value.length > 0) {
          selectedModel.value = presetModels.value[0].id
          onModelChange()
        } else {
          selectedModel.value = ''
          currentApiConfig.value = { apiUrl: '', apiKey: '', modelName: '' }
        }
      }
    }

    /**
     * 获取选中模型的名称
     * @returns 模型名称
     */
    const getSelectedModelName = () => {
      const model = presetModels.value.find(m => m.id === selectedModel.value)
      return model ? model.name : '未知模型'
    }


    /**
     * 发送消息到选定的API
     * 处理用户输入，调用AI模型API并显示回复
     */
    const sendMessage = async () => {
      if (!userInput.value.trim() || loading.value) return
      
      // 检查是否已选择模型
      if (!selectedModel.value) {
        messages.value.push({ 
          role: 'ai', 
          content: '请先选择一个模型。',
          error: 'No model selected'
        })
        return
      }
      
      // 检查API配置
      if (!currentApiConfig.value.apiUrl || !currentApiConfig.value.apiKey) {
        messages.value.push({ 
          role: 'ai', 
          content: '请配置API密钥。您需要先选择模型并配置相应的API密钥。',
          error: 'Missing API configuration'
        })
        return
      }

      // 添加用户消息
      const userMessage = userInput.value.trim()
      messages.value.push({ 
        role: 'user', 
        content: userMessage 
      })
      
      // 保存当前对话到localStorage
      saveCurrentChat()
      
      userInput.value = ''
      loading.value = true
      
      // 滚动到底部
      scrollToBottom()
      
      try {
        // 构建请求消息历史
        const requestMessages = [
          {
            role: 'system',
            content: 'You are a helpful assistant.'
          }
        ]
        
        // 添加历史消息（保留最近的对话上下文）
        const recentMessages = messages.value.slice(-10) // 保留最近10条消息作为上下文
        recentMessages.forEach(msg => {
          requestMessages.push({
            role: msg.role === 'user' ? 'user' : 'assistant',
            content: msg.content
          })
        })

        // 创建流式消息对象
        const streamingMessage: Message = {
          role: 'ai',
          content: '',
          streaming: true
        }
        
        // 添加流式消息到界面
        messages.value.push(streamingMessage)
        streamingMessageRef.value = streamingMessage
        
        // 调用选定的API（流式传输）
        const response = await fetch(currentApiConfig.value.apiUrl, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${currentApiConfig.value.apiKey}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            model: currentApiConfig.value.modelName,
            messages: requestMessages,
            stream: true,
            stream_options: { include_usage: true }
          })
        })

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`)
        }

        // 处理流式响应
        const reader = response.body?.getReader()
        const decoder = new TextDecoder()
        
        if (!reader) {
          throw new Error('无法读取响应流')
        }

        try {
          while (true) {
            const { done, value } = await reader.read()
            
            if (done) {
              // 流式传输完成
              if (streamingMessageRef.value) {
                streamingMessageRef.value.streaming = false
                streamingMessageRef.value = null
              }
              break
            }

            const chunk = decoder.decode(value, { stream: true })
            const lines = chunk.split('\n')

            for (const line of lines) {
              if (line.trim() === '') continue
              if (line.trim() === 'data: [DONE]') {
                // 流式传输结束
                if (streamingMessageRef.value) {
                  streamingMessageRef.value.streaming = false
                  streamingMessageRef.value = null
                }
                break
              }

              if (line.startsWith('data: ')) {
                try {
                  const jsonStr = line.substring(6) // 移除 'data: ' 前缀
                  const data = JSON.parse(jsonStr)
                  
                  if (data.choices && data.choices.length > 0) {
                    const choice = data.choices[0]
                    
                    // 检查是否是结束标记
                    if (choice.finish_reason === 'stop') {
                      if (streamingMessageRef.value) {
                        streamingMessageRef.value.streaming = false
                        streamingMessageRef.value = null
                      }
                      break
                    }
                    
                    // 处理增量内容
                    if (choice.delta && choice.delta.content) {
                      const content = choice.delta.content
                      if (streamingMessageRef.value) {
                        streamingMessageRef.value.content += content
                        // 实时滚动到底部
                        scrollToBottom()
                      }
                    }
                  }
                } catch (parseError) {
                  console.warn('解析流式数据失败:', parseError)
                  // 忽略解析错误，继续处理其他数据
                }
              }
            }
          }
        } finally {
          reader.releaseLock()
        }
        
        // 保存当前对话到localStorage
        saveCurrentChat()
      } catch (error :any) {
        
        let errorMessage = '抱歉，我遇到了问题，请稍后再试。'
        let errorDetail = error.message
        
        if (error.response) {
          // 服务器响应了，但状态码不是2xx
          const status = error.response.status
          if (status === 401 ) {
            errorMessage = 'API或密钥无效，请检查配置。'
          } else if (status === 429) {
            errorMessage = '请求过于频繁，请稍后再试。'
          } else if (status === 500) {
            errorMessage = '服务内部错误。'
          }
          errorDetail = error.response.data?.error?.message || errorDetail
        } else if (error.request) {
          // 请求已发出但没有收到响应
          errorMessage = '无法连接到云服务，请检查网络连接。'
        }
        
        messages.value.push({ 
          role: 'ai', 
          content: errorMessage,
          error: errorDetail
        })
        
        // 保存当前对话到localStorage
        saveCurrentChat()
      } finally {
        loading.value = false
        // 再次滚动到底部
        scrollToBottom()
        
        // 重新聚焦到文本框
        nextTick(() => {
          if (textAreaRef.value) {
            const textarea = textAreaRef.value as HTMLTextAreaElement
            textarea.focus()
          }
        })
      }
    }
    
    /**
     * 保存当前对话到localStorage
     */
    const saveCurrentChat = () => {
      const currentChat = {
        messages: [...messages.value],
        timestamp: Date.now()
      }
      localStorage.setItem('currentChat', JSON.stringify(currentChat))
    }

    /**
     * 滚动到消息底部
     */
    const scrollToBottom = () => {
      nextTick(() => {
        if (messagesContainer.value) {
          const container = messagesContainer.value as HTMLElement
          container.scrollTop = container.scrollHeight
        }
      })
    }

    // 初始化示例消息
    onMounted(() => {
      // 检查是否有缓存的当前对话
      const savedCurrentChat = localStorage.getItem('currentChat')
      if (savedCurrentChat) {
        try {
          const currentChat = JSON.parse(savedCurrentChat)
          if (currentChat.messages && currentChat.messages.length > 0) {
            messages.value = [...currentChat.messages]
          } else {
            messages.value.push({
              role: 'ai',
              content: '你好！有什么可以帮你的吗？'
            })
          }
        } catch (error) {
          console.error('加载当前对话失败:', error)
          messages.value.push({
            role: 'ai',
            content: '你好！有什么可以帮你的吗？'
          })
        }
      } else {
        messages.value.push({
          role: 'ai',
          content: '你好！有什么可以帮你的吗？'
        })
      }

      // 加载保存的模型配置
      const savedModel = localStorage.getItem('selectedModel')
      if (savedModel) {
        selectedModel.value = savedModel
      }
      
      // 加载保存的自定义模型列表
      const savedCustomModels = localStorage.getItem('customModels')
      if (savedCustomModels) {
        try {
          const customModels = JSON.parse(savedCustomModels)
          // 合并默认模型和自定义模型，确保默认模型始终存在
          const defaultModel = presetModels.value.find(m => m.id === 'qwen-plus')
          presetModels.value = [defaultModel, ...customModels.filter((m: any) => m.id !== 'qwen-plus')]
        } catch (error) {
          console.error('加载自定义模型失败:', error)
        }
      }
      
      // 应用选中的模型配置
      onModelChange()
    })

    // 监听连接状态变化
    watch(isConnected, (newValue) => {
      if (newValue && showConnectionWarning.value) {
        showConnectionWarning.value = false
      }
    })

    // 自动调整文本区域高度
    watch(userInput, () => {
      nextTick(() => {

      })
    })

    /**
     * 重置对话
     * 清空当前对话并添加欢迎消息
     */
    const resetChat = () => {
      messages.value = []
      userInput.value = ''
      loading.value = false
      
      // 添加欢迎消息
      messages.value.push({
        role: 'ai',
        content: '你好！有什么可以帮你的吗？'
      })
      
      // 滚动到底部
      scrollToBottom()
      
    }
//  * 加载指定消息
//  * @param newMessages - 要加载的新消息数组
const loadMessages = (newMessages: Message[]) => {
  messages.value = [...newMessages]
  userInput.value = ''
  loading.value = false
  
  // 滚动到底部
  scrollToBottom()
}
    /**
 * 打开信息面板
 */
const openInfoPanel = () => {
  router.push('/info')
}

// 监听自定义事件
onMounted(() => {
  // 监听新对话创建事件
  window.addEventListener('newChatCreated', () => {
    loadMessages([])
  })
  
  // 监听对话选择事件
  window.addEventListener('chatSelected', (event: any) => {
    if (event.detail && event.detail.messages) {
      loadMessages(event.detail.messages)
    }
  })
})

// 暴露方法给外部组件使用
defineExpose({
  loadMessages
})

</script>

<style scoped src="@/styles/ChatWindow.css"></style>